package net.sudot.chess.config;

import java.time.Instant;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;

/**
 * 周期
 * <pre>
 *     起始时间:{startDate}
 *     每{duration} {unit.memo}
 *
 *     如:
 *     起始时间:2018-06-05
 *     每[7日]/[1周]/[1月]
 * </pre>
 *
 * @author tangjialin on 2018-06-04.
 */
public class Cycle {
    /** 单位 */
    public enum CycleUnit {
        DAYS(ChronoUnit.DAYS, "日") {
            @Override
            public LocalDate startDate(LocalDate localDate, LocalDate startDate) {
                return localDate.withDayOfMonth(startDate.getDayOfMonth());
            }
        },
        WEEKS(ChronoUnit.WEEKS, "周") {
            @Override
            public LocalDate startDate(LocalDate localDate, LocalDate startDate) {
                return localDate.with(TemporalAdjusters.previousOrSame(startDate.getDayOfWeek()));
            }
        },
        MONTHS(ChronoUnit.MONTHS, "月") {
            @Override
            public LocalDate startDate(LocalDate localDate, LocalDate startDate) {
                return localDate.withDayOfMonth(startDate.getDayOfMonth());
            }
        };
        private String memo;
        private TemporalUnit value;

        CycleUnit(TemporalUnit value, String memo) {
            this.memo = memo;
            this.value = value;
        }

        public String memo() {
            return memo;
        }

        public TemporalUnit value() {
            return value;
        }

        public abstract LocalDate startDate(LocalDate localDate, LocalDate startDate);

    }

    /** 起始时间 */
    private Instant startDate;
    /** 持续时间 */
    private Integer duration;
    /** 周期类型 */
    private CycleUnit unit;

    public Instant getStartDate() {
        return startDate;
    }

    public Cycle setStartDate(Instant startDate) {
        this.startDate = startDate;
        return this;
    }

    public Cycle setStartDateText(String startDateText) {
        this.startDate = OffsetDateTime.parse(startDateText).toInstant();
        return this;
    }

    public Integer getDuration() {
        return duration;
    }

    public Cycle setDuration(Integer duration) {
        this.duration = duration;
        return this;
    }

    public CycleUnit getUnit() {
        return unit;
    }

    public Cycle setUnit(CycleUnit unit) {
        this.unit = unit;
        return this;
    }

    /**
     * 周期计算
     *
     * @author tangjialin on 2018-06-12.
     */
    public static class CycleCalc {
        private Instant startDate;
        private Instant endDate;

        /**
         * @param date  基准时间
         * @param cycle 周期
         */
        public CycleCalc(LocalDate date, Cycle cycle) {
            LocalDate startLocalDate = cycle.getUnit().startDate(date, cycle.getStartDate().atZone(ZoneId.systemDefault()).toLocalDate());

            ZoneId zoneId = ZoneId.systemDefault();
            startDate = startLocalDate.atStartOfDay(zoneId).toInstant();
            endDate = startLocalDate.plus(cycle.getDuration(), cycle.getUnit().value()).atStartOfDay(zoneId).toInstant();
        }

        /**
         * 以某个时间为基准,获取其周期的开始时间
         *
         * @return 返回其周期的开始时间
         */
        public Instant getStartDateWidth() {
            return startDate;
        }

        /**
         * 以某个时间为基准,获取其周期的结束时间
         *
         * @return 返回其周期的结束时间
         */
        public Instant getEndDateWidth() {
            return endDate;
        }

    }
}
